home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr52
/
pdxvie.zip
/
READDB.PRG
< prev
next >
Wrap
Text File
|
1993-04-01
|
20KB
|
694 lines
* This program has been altered by Kevin S. Gallagher
* Compile...: /a/w/m/n
* Link......: warplink
*╔══════════════════════════════════════════════════════════════════╗*
*║ System Name: Paradox (r) viewing program ║*
*║ Module Name: READDB.PRG ║*
*║ ║*
*║ Description: Program to show that you can basically browse ║*
*║ anything with a little imagination and a lot ║*
*║ of patience (a lot of patience) ║*
*║ ║*
*║ Notes......: **** THIS IS NOT AN RDD **** ║*
*║ ║*
*║ Syntax: READDB <database>.db ║*
*║ ║*
*║ Read the READDB.TXT file please. ║*
*║ ** Compile with the /w/a switches. ** ║*
*║ ║*
*║ Author.....: Micheal Todd Charron ║*
*║ ║*
*║ Date.......: April 15, 1990 ║*
*║ ║*
*║ History....: I kept telling user groups that you can ║*
*║ use TBrowse to browse anything you want to. ║*
*║ I decided that before the Paradox (r) RDD ║*
*║ came out that I would make a Paradox (r). ║*
*║ viewer. Two weeks of working on it when I ║*
*║ had time. ║*
*║ ║*
*║ Copyright..: (c) Micro Tech Consultant Services, 1991 ║*
*║ (c) The people at Nantucket Canada, 1991 ║*
*║ Is this possible? ║*
*╚══════════════════════════════════════════════════════════════════╝*
#include "inkey.ch"
#include "funcs.ch"
#include "its501.ch"
************************************************************************
// Defines the locations of data in the main array \\
#define mRecSize aPDXInfo[ 1 ]
#define mNoInSection aPDXInfo[ 2 ]
#define mNoOfRecords aPDXInfo[ 3 ]
#define mNoOfFields aPDXInfo[ 4 ]
#define mFieldInfo aPDXInfo[ 5 ]
// Defines the Ascii representation of Field Types \\
#define mTypeNumeric 6
#define mTypeCurrency 5
#define mTypeInteger 3
#define mTypeDate 2
#define mTypeCharacter 1
// Defines variables that are visable to the whole .PRG \\
// Array which contains the database structure information \\
STATIC aPDXInfo
// Character string of a complete record \\
STATIC cPDXRecord
// Numeric variable with the database's file handle in it \\
STATIC nRead
FUNCTION Main( cFileName )
LOCAL nI, nKey, nPDXPos := 1, nRecCountLen
// Defines my main TBrowse table \\
LOCAL oBrowse := TBROWSENEW( 2, 3, 19, 74 )
// Turns the cursor off and clears the screen \\
SETCURSOR( 0 )
CLS
// Open the database file and assign the file handle to `nRead' \\
nRead := FOPEN( cFileName )
// Check to see if an error has occurred \\
IF nRead == -1
? 'File cannot be read!'
QUIT
ENDIF
// Psuedo function which draws a background and displays message \\
Panel( .T. )
// Draws a double lined box with a shadow under it \\
Shad( 1, 2, 21, 75, .T., 'w+/b' )
SETCOLOR( 'gr+/b' )
// Displays the database's name in the info area
@20, 5 SAY UPPER( cFileName )
// Defines the TBrowse's color \\
oBrowse:COLORSPEC := 'w+/b'
// Defines the TBrowse's column, heading, and footing separators \\
oBrowse:COLSEP := ' │ '
oBrowse:HEADSEP := '═╤═'
oBrowse:FOOTSEP := '═╧═'
// Retrieves the database's file structure \\
aPDXInfo := PDXHeader()
// Adds new columns to the TBrowse \\
FOR nI := 1 TO mNoOfFields
// Macro expands the code block to use the iteration \\
// value of the counter \\
oBrowse:ADDCOLUMN( TBCOLUMNNEW( mFieldInfo[ nI, 4 ],;
&( '{ || PDXField(' + LTRIM( STR( nI ) ) + ') }' ) ) )
NEXT nI
// Determines how many spaces the number of records will take \\
nRecCountLen := LEN( LTRIM( STR( mNoOfRecords ) ) )
// Display the number of records
@20, 72 - nRecCountLen - 5 SAY '1 of ' + LTRIM( STR( mNoOfRecords ) )
// Defines the code block that moves through the PDX file \\
oBrowse:SKIPBLOCK := { | nMove | SkipPDX( nMove, @nPDXPos ) }
// Returns the TBrowse to the first record \\
oBrowse:GOTOPBLOCK := { || nPDXPos := 1, FSEEK( nRead, 2054, 0 ),;
cPDXRecord := ReadIn( nRead, mRecSize ) }
// Positions the file pointer to the first record \\
FSEEK( nRead, 2054, 0 )
// Reads in the record to the character string \\
cPDXRecord := ReadIn( nRead, mRecSize )
DO WHILE .T.
// Runs through the loop until the TBrowse \\
// is Stable \\
DO WHILE ! ( oBrowse:STABILIZE() )
ENDDO
// Unfortunately this is one of those weird ones I \\
// cannot explain. The color of the next @...SAY \\
// seems to be taken from the COLORSPEC, I think. \\
// If I put SETCOLOR() on the next line everthing \\
// works fine.
SETCOLOR()
// Displays the current record number \\
@20, 72 - ( nRecCountLen * 2 ) - 4 SAY PADL( nPDXPos,;
nRecCountLen )
// Waits for a Keypress \\
nKey := INKEY( 0 )
DO CASE
// Calls up a the main help screen \\
CASE nKey == K_F1
HelpScreen( 1 )
// Calls up the field info screen \\
CASE nKey == K_F2
FieldDisplay()
// Moves up one row \\
CASE nKey == K_UP
oBrowse:UP()
// Moves down one row \\
CASE nKey == K_DOWN
oBrowse:DOWN()
// Moves right one column \\
CASE nKey == K_RIGHT
oBrowse:RIGHT()
// Moves left one column \\
CASE nKey == K_LEFT
oBrowse:LEFT()
// Moves down one screen \\
CASE nKey == K_PGDN
oBrowse:PAGEDOWN()
// Moves up one screen \\
CASE nKey == K_PGUP
oBrowse:PAGEUP()
// Moves to the first record \\
CASE nKey == K_HOME
oBrowse:GOTOP()
// Ask the user whether to exit or not \\
CASE nKey == K_F10
IF TimeToExit()
EXIT
ENDIF
ENDCASE
ENDDO
// Closes the database file \\
FCLOSE( nRead )
// Draws the credits screen \\
Credit()
// Turns the cursor off \\
SETCURSOR( 1 )
// Ends the program \\
RETURN Nil
* * * *
*
* Function ReadIn()
*
// Reads in `nLength' of bytes from the file and returns them. This \\
// differs in FREADSTR() because it does not stop at a null character. \\
FUNCTION ReadIn( nRead, nLength )
LOCAL cBuffer := SPACE( nLength )
FREAD( nRead, @cBuffer, nLength )
RETURN cBuffer
* * * *
*
* Function IEEEToNumb()
*
// Converts IEEE format numbers to floating point \\
// Don't ask me to explain this function because I won't. \\
FUNCTION IEEEToNumb( cNum )
LOCAL lNeg
LOCAL nPower, nMant
nPower := ( ( ASC( SUBSTR( cNum, 1, 1 ) ) % 128 ) * 16 ) +;
INT( ASC( SUBSTR( cNum, 2, 1 ) ) / 16 ) - 1023
lNeg := ( ASC( SUBSTR( cNum, 1, 1 ) ) / 16 ) < 8
nMant := 1 + ( ( ASC( SUBSTR( cNum, 2, 1 ) ) % 16 ) / 16 ) +;
( BIN2W( SUBSTR( cNum, 4, 1 ) +;
SUBSTR( cNum, 3, 1 ) ) / ( 65536 * 16 ) ) +;
( BIN2W( SUBSTR( cNum, 6, 1 ) +;
SUBSTR( cNum, 5, 1 ) ) / ( 65536 * 65536 * 16 ) ) +;
( BIN2W( SUBSTR( cNum, 8, 1 ) +;
SUBSTR( cNum, 7, 1 ) ) / ( 65536 * 65536 * 65536 * 16 ) )
RETURN ( nMant * ( 2 ^ nPower ) ) * IF( lNeg, -1, 1 )
* * * *
*
* Function Chr2Numb()
*
// Converts two and four byte ascii groupings to numbers \\
FUNCTION Chr2Numb( cVar, nLen )
LOCAL nI, nRet_Val
IF nLen == 2
nRet_Val := BIN2I( RIGHT( cVar, 1 ) + LEFT( cVar, 1 ) )
ELSE
nRet_Val := BIN2W( RIGHT( cVar, 1 ) + SUBSTR( cVar, 3, 1 ) +;
SUBSTR( cVar, 2, 1 ) + LEFT( cVar, 1 ) )
ENDIF
RETURN nRet_Val
* * * *
*
* Function PDXField()
*
// Returns the proper data for the function located in the \\
// TBCOLUMNNEW code block. \\
FUNCTION PDXField( nField )
LOCAL xRetBlock
// Pulls the info for the current field from aPDXInfo \\
LOCAL nLength := mFieldInfo[ nField, 3 ],;
nStart := mFieldInfo[ nField, 2 ],;
nType := mFieldInfo[ nField, 1 ]
DO CASE
CASE nType == mTypeNumeric
// Converts IEEE format number to floating point number \\
// and then transforms it with the set picture string \\
xRetBlock := TRANSFORM( IEEEToNumb( SUBSTR( cPDXRecord,;
nStart, 8 ) ), "99999999.99" )
CASE nType == mTypeCurrency
// Converts IEEE format number to floating point number \\
// and then transforms it with the set picture string \\
xRetBlock := TRANSFORM( IEEEToNumb( SUBSTR( cPDXRecord,;
nStart, 8 ) ), "$99,999,999.99" )
CASE nType == mTypeInteger
// Converts the two ascii characters to a integer and \\
// adds 32768 to that integer \\
xRetBlock := 32768 + Chr2Numb( SUBSTR( cPDXRecord, nStart,;
2 ), 2 )
CASE nType == mTypeDate
// Converts the four Ascii characters to an integer and \\
// adds the date September 30th, 1974 to it \\
xRetBlock := Chr2Numb( SUBSTR( cPDXRecord, nStart, 4 ), 4 ) +;
CTOD( "09/30/74" )
OTHERWISE
// Assigns the character string \\
xRetBlock := SUBSTR( cPDXRecord, nStart, nLength )
ENDCASE
RETURN xRetBlock
* * * *
*
* Function SkipPDX()
*
// Defines the movement of the TBrowse and positions the file pointer \\
FUNCTION SkipPDX( nMove, nPDXPos )
LOCAL nNoOfSection, nPosInSection
// Checks to see if the TBrowse is requesting a move past the \\
// number of records and if so, restricts the tbrowse's movements \\
IF nMove > 0
// If the current position plus the requested move is \\
// greater than the number of records, return the number \\
// of records minus the current record position \\
IF ( nPDXPos + nMove ) > mNoOfRecords
nMove := mNoOfRecords - nPDXPos
ENDIF
ELSE
// If the current position plus the requested move is \\
// less than the first record, return the number of \\
// records to move back to the first \\
IF ( nPDXPos + nMove ) < 1
nMove := 1 - nPDXPos
ENDIF
ENDIF
// Add the number of records that the TBrowse is allowed to \\
// move to the current record position \\
nPDXPos += nMove
// If the TBrowse will move at all, reposition the file pointer \\
IF nMove != 0
// Determines which 2048 byte section the record is in \\
nNoOfSection := INT( nPDXPos / mNoInSection ) +;
IF( nPDXPos / mNoInSection == 0, 0, 1 )
// Determines which record in the 2048 byte section it is \\
nPosInSection := ( nPDXPos - ( ( nNoOfSection - 1 ) *;
mNoInSection ) - 1 )
IF nPosInSection == -1
nPosInSection := 0
ENDIF
// Move the file pointer \\
FSEEK( nRead, ( nNoOfSection * 2048 ) + 6 +;
( nPosInSection * mRecSize ), 0 )
// Read in the current record \\
cPDXRecord := ReadIn( nRead, mRecSize )
ENDIF
RETURN nMove
* * * *
*
* Function PDXHeader()
*
// Retrieves the Header information and adds it to an array \\
FUNCTION PDXHeader()
LOCAL aPDXInfo := {}
LOCAL nFileLoc, nI, nLoc := 1
// Adds the record size to the array \\
AADD( aPDXInfo, BIN2L( ReadIn( nRead, 3 ) ) )
// Adds the number of records per section \\
AADD( aPDXInfo, INT( ( 2042/mRecSize + 1 ) ) )
FSEEK( nRead, 6, 0 )
// Adds the record size \\
AADD( aPDXInfo, BIN2L( ReadIn( nRead, 4 ) ) )
FSEEK( nRead, 33, 0 )
// Adds the number of fields \\
AADD( aPDXInfo, BIN2I( ReadIn( nRead, 2 ) ) )
* // Future expansion for records larger that 2048
* AADD( aPDXInfo, ( INT( mRecSize / 1024 ) + 1 ) * 1024 )
FSEEK( nRead, 88, 0 )
// Will contain the reference to the Field Info \\
// multi-dimensional array. \\
AADD( aPDXInfo, {} )
FOR nI := 1 TO mNoOfFields
// Adds the field type to the array \\
AADD( mFieldInfo, { ASC( ReadIn( nRead, 1 ) ) } )
// Adds the location in the cPDXRecord string of the field \\
AADD( mFieldInfo[ nI ], nLoc )
// Adds the length in the cPDXRecord string of the field \\
AADD( mFieldInfo[ nI ], ASC( ReadIn( nRead, 1 ) ) )
// Assigns the new location to nLoc \\
nLoc += mFieldInfo[ nI, 3 ]
NEXT nI
// Repositions the file pointer to the start of the field names \\
nFileLoc := FSEEK( nRead, ( ( mNoOfFields + 1 ) * 4 ) + 79, 1 )
FOR nI := 1 TO mNoOfFields
// Adds the field name \\
AADD( mFieldInfo[ nI ], FREADSTR( nRead, 26 ) )
nFileLoc := FSEEK( nRead, nFileLoc +;
LEN( mFieldInfo[ nI, 4 ] ) + 1, 0 )
NEXT nI
// Returns the database information \\
RETURN aPDXInfo
* * * *
*
* Function FieldDisplay()
*
// Displays the field information in a TBrowse \\
FUNCTION FieldDisplay()
LOCAL SaveFullScreen()
LOCAL cDefColor := SETCOLOR( 'gr+/br' )
LOCAL oBrowse, oColumn
LOCAL nFieldLen, nFieldPos := 1, nInfoRow, nKey, nNoOfRows, nStartRow
// Determines the number of rows the tbrowse will need
nNoOfRows := MIN( mNoOfFields, 7 ) + 1
// Determines the top line of the TBrowse \\
nStartRow := INT( ( 24 - nNoOfRows ) / 2 ) - 2
// Determines the line for the display of the number of fields \\
nInfoRow := nStartRow + nNoOfRows + 2
// Creates the object for the field info browse \\
oBrowse := TBROWSENEW( nStartRow, 14, nInfoRow - 1, 61 )
// Draws a shadowed box for the field info browse \\
BoxShad( ( nStartRow - 1 ), 12, ( nInfoRow + 1 ), 63,;
'w+/br' )
@nInfoRow, 14 SAY 'FIELDS'
// Determines the amount of space the number of fields will need \\
nFieldLen := LEN( LTRIM( STR( mNoOfFields ) ) )
@nInfoRow, 62 - nFieldLen - 5 SAY '1 of ' + LTRIM( STR( mNoOfFields ) )
// Defines the field browse's Head, Column and Footing separators \\
oBrowse:HEADSEP := '─┬─'
oBrowse:COLSEP := ' │ '
oBrowse:FOOTSEP := '─┴─'
// Creates the field name column object \\
oColumn := TBCOLUMNNEW( PADC( 'NAME', 25 ),;
{ || PADR( mFieldInfo[ nFieldPos, 4 ], 25 ) } )
// Specifies the color for the column data \\
oColumn:COLORBLOCK := { || { 3, 2 } }
// Adds the column object to the TBrowse \\
oBrowse:ADDCOLUMN( oColumn )
// Creates the field type column object \\
oColumn := TBCOLUMNNEW( PADC( 'TYPE', 12 ),;
{ || FieldType( mFieldInfo[ nFieldPos, 1 ] ) } )
// Specifies the color for the column data \\
oColumn:COLORBLOCK := { || { 3, 2 } }
// Adds the column object to the TBrowse \\
oBrowse:ADDCOLUMN( oColumn )
// Creates the field length column object \\
// Only AlphaNumeric ( character ) fields have user \\
// definable lengths \\
oColumn := TBCOLUMNNEW( 'LEN',;
{ || IF( mFieldInfo[ nFieldPos, 1 ] == mTypeCharacter,;
PADL( mFieldInfo[ nFieldPos, 3 ], 3 ), ' ' ) } )
// Specifies the color for the column data \\
oColumn:COLORBLOCK := { || { 3, 2 } }
// Adds the column object to the TBrowse \\
oBrowse:ADDCOLUMN( oColumn )
// Specifies the overall colors of the TBrowse \\
// NOTE: The fourth color is for a Clipper 5.0 bug \\
oBrowse:COLORSPEC := 'gr+/br, w+/n, w+/br, n/n'
// Defines the movement through the array \\
oBrowse:SKIPBLOCK :=;
{ | nMove | SkipArray( nMove, @nFieldPos, LEN( mFieldInfo ) ) }
DO WHILE .T.
// Runs through the loop until the TBrowse \\
// is Stable \\
DO WHILE ! ( oBrowse:STABILIZE() )
ENDDO
// Colors all cells in the current row 'w+/n' \\
oBrowse:COLORRECT( { oBrowse:ROWPOS, 1, oBrowse:ROWPOS,;
oBrowse:COLCOUNT }, { 2, 2 } )
// Displays the current field number \\
@nInfoRow, 62 - ( nFieldLen * 2 ) - 4 SAY PADL( nFieldPos,;
nFieldLen )
// Waits for key input \\
nKey := INKEY( 0 )
// Colors all cells in the current row as their \\
// default colors \\
oBrowse:COLORRECT( { oBrowse:ROWPOS, 1, oBrowse:ROWPOS,;
oBrowse:COLCOUNT }, { 3, 2 } )
DO CASE
// Displays a help screen for the field browse \\
CASE nKey == K_F1
HelpScreen( 2 )
// Do I have to explain the follow four cases? \\
CASE nKey == K_UP
oBrowse:UP()
CASE nKey == K_DOWN
oBrowse:DOWN()
CASE nKey == K_PGDN
oBrowse:PAGEDOWN()
CASE nKey == K_PGUP
oBrowse:PAGEUP()
// Return to the main browse \\
CASE nKey == K_ESC
EXIT
ENDCASE
ENDDO
SETCOLOR( cDefColor )
RestFullScreen()
RETURN Nil
* * * *
*
* Function FieldType()
*
// Returns the field type according to its ascii representation \\
FUNCTION FieldType( nFieldType )
LOCAL cRetType
DO CASE
CASE nFieldType == mTypeCharacter
cRetType := 'AlphaNumeric'
CASE nFieldType == mTypeNumeric
cRetType := 'Number '
CASE nFieldType == mTypeInteger
cRetType := 'Short Number'
CASE nFieldType == mTypeCurrency
cRetType := 'Currency '
CASE nFieldType == mTypeDate
cRetType := 'Date '
ENDCASE
RETURN cRetType
* * * *
*
* Function SkipArray()
*
// Controls movement through the browse.
FUNCTION SkipArray( nMove, nArrPos, nArrayLength )
// Checks to see if the movement will be outside the bounds
// of the array and if so, restricts the tbrowse's movements.
IF nMove > 0
// If the current position plus the requested move is
// greater than the length of the array return the number
// of elements left in the array.
IF ( nArrPos + nMove ) > nArrayLength
nMove := nArrayLength - nArrPos
ENDIF
ELSE
// If the current position plus the requested move is
// pass the start of the array, return the number of
// elements to the start of the array.
IF ( nArrPos + nMove ) < 1
nMove := 1 - nArrPos
ENDIF
ENDIF
// Add the number to move to the array position
nArrPos += nMove
RETURN nMove
* * * *
*
* Function TimeToExit()
*
// Exit Dialog Box
FUNCTION TimeToExit()
LOCAL cDefColor := SETCOLOR( 'w+/r' ),;
cFullScrn := SAVESCREEN( 0, 0, 24, 79 )
LOCAL nExitCh := 1
BoxShad( 8, 30, 12, 48, 'w+/r' )
@9, 33 SAY 'Do You Really'
@10, 33 SAY 'Want to Exit?'
@11, 34 PROMPT ' YES '
@11, 41 PROMPT ' NO '
MENU TO nExitCh
SETCOLOR( cDefColor )
RESTSCREEN( 0, 0, 24, 79, cFullScrn )
RETURN IF( nExitCh == 1, .T., .F. )
* * * *
*
* Function HelpScreen()
*
// Pops up a help screen \\
Function HelpScreen( nHelpScreen )
LOCAL SaveFullScreen()
LOCAL cDefColor := SETCOLOR( 'r+/r' )
LOCAL nI
DO CASE
CASE nHelpScreen == 1
BoxShad( 5, 25, 17, 51, 'w+/r' )
SETCOLOR( 'r+/r' )
FOR nI := 7 TO 15
@nI, 35 SAY '-'
NEXT nI
@6, 27 TO 16, 49
@13, 27 SAY '├─────────────────────┤'
SETCOLOR( 'gr+/r' )
@7, 33 SAY CHR( 25 )
@8, 33 SAY CHR( 24 )
@9, 30 SAY 'PgDn'
@10, 30 SAY 'PgUp'
@11, 33 SAY CHR( 26 )
@12, 33 SAY CHR( 27 )
@14, 32 SAY 'F2'
@15, 31 SAY 'F10'
SETCOLOR( 'w+/r' )
@7, 37 SAY 'Down'
@8, 37 SAY 'Up'
@9, 37 SAY 'Page Down'
@10, 37 SAY 'Page Up'
@11, 37 SAY 'Right'
@12, 37 SAY 'Left'
@14, 37 SAY 'Field Info'
@15, 37 SAY 'Exit'
CASE nHelpScreen == 2
BoxShad( 6, 25, 15, 52, 'w+/r' )
SETCOLOR( 'r+/r' )
FOR nI := 8 TO 13
@nI, 35 SAY '-'
NEXT nI
@7, 27 TO 14, 50
@12, 27 SAY '├──────────────────────┤'
SETCOLOR( 'gr+/r' )
@8, 33 SAY CHR( 25 )
@9, 33 SAY CHR( 24 )
@10, 30 SAY 'PgDn'
@11, 30 SAY 'PgUp'
@13, 31 SAY 'ESC'
SETCOLOR( 'w+/r' )
@8, 37 SAY 'Down'
@9, 37 SAY 'Up'
@10, 37 SAY 'Page Down'
@11, 37 SAY 'Page Up'
@13, 37 SAY 'Main Screen'
ENDCASE
PressAnyKey()
RestFullScreen()
SETCOLOR( cDefColor )
RETURN Nil